include(['materials.Material', 'Matrix2d'], 

function(){
	
	declare('Node');
	Node = PClass.create({
		children  : null,
		parent    : null,
		matrix2d  : null,
		active    : 0,
		material  : Material.standard,
		init : function(mesh){
			this.matrix2d = new Matrix2d();
			this.children = [];
			
			if( mesh ){
				this.children.push(mesh);
			}
		},
		points : function(){
			var results = [];
			this.children.forEach(function(item){
				item.points.forEach(function(point){
					this.matrix2d.apply( point );
					results.push( point );				
				});			
			});
			return results;
		},
        toWorldCoordinate : function( localCoordinate ){
            var store = new Vector2();
            this.matrix2d.apply(localCoordinate, store);
            if( parent && parent.toWorldCoordinate )
                store = parent.toWorldCoordinate(store);
            return store;
        },
        toLocalCoordinates : function( worldCoordinate ){
            return this._normalizePoint( worldCoordinate );
        },
		_normalizePoint : function(point){
			var store = new Vector2();
			var inv = this.matrix2d.invert();
			inv.apply(point, store);
			return store;
		},
		intersects : function( point, tolerance ){
			var tmp = this._normalizePoint(point);
			var results = [];
			var selfish = this;
			this.children.forEach(function(item){
				var matches = item.intersects(tmp, tolerance);
				if( matches ){
					matches.forEach(function(i){
						results.push({node:selfish, child:i}); 
					})
				}
			});
			if( results.length == 0 ) return null;
			return results;
		},
		intersectsChild : function( point, child, tolerance ){
			var tmp = this._normalizePoint(point);
			var results = [];
			var selfish = this;
			var matches = child.intersects(tmp, tolerance);
			if( matches ){
				matches.forEach(function(i){
					results.push({node:selfish, child:i}); 
				})
			}		
			if( results.length == 0 ) return null;
			return results;
		},	
		render : function( gw ){
			var c = gw.c;
			c.save();
			var m2d = this.getWorldTransform();
			var material = this.material;
			c.setTransform(m2d.x1,m2d.y1, m2d.x2, m2d.y2, m2d.x3,m2d.y3);
			for(var member in this.children){
				if( this.children[member].render )
					material.render(gw, this.children[member]);
			}
			this.children.forEach(function(item){
				material.render(gw, item);
			});
			c.restore();
		},
		renderChild : function( gw, child ){
			var c = gw.c;
			c.save();
			c.transform(this.matrix2d.x1,this.matrix2d.y1, this.matrix2d.x2, this.matrix2d.y2, this.matrix2d.x3,this.matrix2d.y3);
			this.material.render(gw, child);
			c.restore();
		},
		translate : function(x, y){
			this.matrix2d.translate(x,y);
		},
		setTranslation : function(x,y){
			this.matrix2d.setTranslation(x,y);
		},	
		scale : function(x, y){
			this.matrix2d.scale(x, y);
		},
		shear : function(x, y){
			this.matrix2d.shear(x, y);
		},
		rotate : function( degrees ){
			this.matrix2d.rotate(degrees);
		},
		setTransform : function(matrix){
			this.matrix2d.reset(matrix);
		},
		setActive : function(value){
			this.active = value;
			this.children.forEach(function(item){
				item.setActive( value );
			});
		},
		setParent : function(value){
			this.parent = value;
		},
		getParent : function(){
			return this.parent;
		},
		addChild : function(value){
			if( value.setParent ) value.setParent(this);
			this.children.push(value);
		},
		getWorldTransform : function(){
			var m2d = this.matrix2d.clone();
			if( this.parent ){
				var pm2d = this.parent.getWorldTransform(); 
				m2d = m2d.multiply(pm2d)
			}
			return m2d;
		},
		save : function(){
			if(!this._stash) this._stash = [];
			this._stash.push( this.matrix2d.clone() );
		},
		restore : function(){
			if(this._stash)
				this.matrix2d = this._stash.pop();
		},
		boundingBox : function(){
			var results = {min:{x:10000, y:10000}, max:{x:-10000,y:-10000}};
			var min = results.min;
			var max = results.max;
			var selfish = this;
			for(var member in this.children){
				var item = this.children[member];
				if( item && item.boundingBox ){
					var box = item.boundingBox();
					if( box.min.x < min.x ) min.x = box.min.x;
					if( box.max.x > max.x ) max.x = box.max.x;
					if( box.min.y < min.y ) min.y = box.min.y;
					if( box.max.y > max.y ) max.y = box.max.y;
				}
			}
			this.matrix2d.apply(min, results.min);
			this.matrix2d.apply(max, results.max);
			return results;
		}	
	}, 'Node')
	
});